package com.yeyks.commonReference.service.account.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.account.dal.dao.AccountInfoMapper;
import com.yeyks.account.dal.domain.AccountInfo;
import com.yeyks.account.dal.domain.SysRole;
import com.yeyks.account.dto.AccountDTO;
import com.yeyks.account.param.AccountInfoQueryParam;
import com.yeyks.account.service.SysAppMenuService;
import com.yeyks.account.service.SysRoleService;
import com.yeyks.account.service.SysUserRoleService;
import com.yeyks.common.appcommon.dto.AppAddressCode;
import com.yeyks.common.appcommon.dto.AppAddressDTO;
import com.yeyks.common.appcommon.dto.AppRouteDTO;
import com.yeyks.common.appcommon.dto.account.AppAccountDTO;
import com.yeyks.common.appcommon.json.JsonBankInfo;
import com.yeyks.common.appcommon.json.JsonHotelPayAccounts;
import com.yeyks.common.appcommon.param.account.*;
import com.yeyks.common.appcommon.result.CommonPage;
import com.yeyks.common.appcommon.result.CommonResult;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.base.PageResult;
import com.yeyks.common.constants.AccountType;
import com.yeyks.common.em.ResponseStatus;
import com.yeyks.common.em.SysRoleType;
import com.yeyks.common.em.accountinfo.AccountInfoRateEnum;
import com.yeyks.common.em.accountinfo.AccountInfoTypeEnum;
import com.yeyks.common.exception.OftenFiledException;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.exception.TokenInvalidException;
import com.yeyks.common.param.member.MemberCardOperatorListParam;
import com.yeyks.common.result.member.MemberCardOperatorListResult;
import com.yeyks.common.utils.FormatUtils;
import com.yeyks.common.utils.JWTUtil;
import com.yeyks.common.utils.ObjectConvertUtil;
import com.yeyks.common.utils.apputil.bean.MyBeanUtils;
import com.yeyks.common.utils.apputil.redis.RedisService;
import com.yeyks.common.utils.apputil.rediskey.BuilderKey;
import com.yeyks.commonReference.pojo.dto.AddSysUserDTO;
import com.yeyks.commonReference.pojo.param.AddBusinessParam;
import com.yeyks.commonReference.pojo.param.QueryBusinessParam;
import com.yeyks.commonReference.service.account.AccountInfoService;
import com.yeyks.commonReference.service.consumer.MemberCardService;
import com.yeyks.commonReference.service.hotel.HotelInfoService;
import com.yeyks.commonReference.service.hotel.RoomInfoService;
import com.yeyks.commonReference.service.message.MessageService;
import com.yeyks.commonReference.service.vip.AccountVipSalerRelationService;
import com.yeyks.commonReference.service.vip.VipCommissionRateConfigService;
import com.yeyks.consumer.dal.dao.UserInfoMapper;
import com.yeyks.consumer.dal.domain.MemberCard;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.hotel.dal.domain.HotelInfo;
import com.yeyks.hotel.dal.domain.RoomInfo;
import com.yeyks.other.service.AddressDivisionService;
import com.yeyks.vip.dal.dao.AccountVipSalerRelationMapper;
import com.yeyks.vip.dal.domain.AccountVipSalerRelation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.yeyks.common.utils.apputil.rediskey.RedisKey.ACCOUNT_TOKEN;


/**
 * <p>
 * 后台帐户表 服务实现类
 * </p>
 *
 * @author yun
 * @since 2019-06-25
 */
@Service
@Slf4j
public class AccountInfoServiceImpl extends ServiceImpl<AccountInfoMapper, AccountInfo> implements AccountInfoService {

    @Autowired
    AccountInfoMapper accountInfoMapper;
    @Autowired
    RoomInfoService roomInfoService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    MessageService messageService;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private MemberCardService memberCardService;
    @Autowired
    private AddressDivisionService addressDivisionService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SysAppMenuService sysAppMenuService;
    @Autowired
    private VipCommissionRateConfigService vipCommissionRateConfigService;
    @Autowired
    private HotelInfoService hotelInfoService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private AccountVipSalerRelationMapper accountVipSalerRelationMapper;
    @Autowired
    private AccountVipSalerRelationService accountVipSalerRelationService;

    @Override
    public Integer token2UserId(String token) {
        //return Integer.parseInt(getUserId(token));
        return Integer.parseInt(JWTUtil.getUserId(token));
    }


    @Override
    public boolean roomHavePermission(Integer loginUserId, List<Integer> ids) {

        List<RoomInfo> roomInfoList = roomInfoService.searchRoomByOperator(loginUserId);

        for (Integer i : ids) {

            boolean found = false;
            for (RoomInfo roomInfo : roomInfoList) {
                if (roomInfo.getId().intValue() == i.intValue()) {
                    found = true;
                    break;
                }
            }

            if (!found) {
                return false;
            }
        }

        return true;
    }


    @Override
    public AccountInfo token2AccountInfo(String token) {
        Arguments.strIsNull(token, "token不能为空");
        AccountInfo accountInfo = null;
        try {
            Integer userId = token2UserId(token);
            accountInfo = accountInfoMapper.selectByPrimaryKey(userId);
        } catch (ServiceException e) {
            log.info("token过期或token无效,token = {}", token);
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.info("通过用户token获取用户失败，token=" + token + "，错误信息：" + e.getMessage());
        }
        if (accountInfo == null) {
            log.info("该用户不存在，token={}", token);
            throw new ServiceException(-1, "该用户不存在");
        }
        return accountInfo;
    }


//    @Override
//    public void setPrecentage(Integer admin, Integer branch, Integer city) throws Exception {
//        int rec = accountInfoMapper.setPrecentage(admin, branch, city);
//        if (rec == 0) {
//            throw new Exception("updated 0 row.");
//        }
//    }

    @Override
    public List<AccountInfo> queryPageList(AccountInfoQueryParam accountInfoQueryParam) {
        List<AccountInfo> accountInfos = accountInfoMapper.queryList(accountInfoQueryParam);
        return accountInfos;
    }

    @Override
    public List<AccountInfo> querySubUserList(AccountInfoQueryParam accountInfoQueryParam) {
        List<AccountInfo> accountInfos = accountInfoMapper.querySubUserList(accountInfoQueryParam);
        return accountInfos;
    }

    @Override
    public int queryListCount(AccountInfoQueryParam accountInfoQueryParam) {
        Integer count = accountInfoMapper.queryListCount(accountInfoQueryParam);
        if (count == null) return 0;
        return count;
    }

    @Override
    public int querySubUserListCount(AccountInfoQueryParam accountInfoQueryParam) {
        Integer count = accountInfoMapper.querySubUserListCount(accountInfoQueryParam);
        if (count == null) {
            return 0;
        }
        return count;
    }

    private List<AccountDTO> tranformAccountDTO(List<AccountInfo> accountInfos) {
        List<AccountDTO> accountDTOS = new ArrayList<>();
        for (AccountInfo accountInfo : accountInfos) {
            AccountDTO accountDTO = ObjectConvertUtil.convertObject(accountInfo, AccountDTO.class);
            Integer countChildren = accountInfoMapper.countOfChildren(accountInfo.getId(), null, null);
            accountDTO.setGrandchildrenCount(countChildren);
            accountDTOS.add(accountDTO);
        }
        return accountDTOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(AccountInfo loginUser, AddSysUserDTO addUser) {
        //如果是子账号创建操作
        if (null != loginUser.getManagerId()) {
            loginUser.setParentId(loginUser.getManagerId());
            loginUser.setManagerId(null);
        } else {
            loginUser.setParentId(loginUser.getId());
            loginUser.setManagerId(null);
        }
        loginUser.setPassword(addUser.getPassword());
        loginUser.setUsername(addUser.getUsername());
        loginUser.setName(addUser.getName());
        loginUser.setArea(addUser.getArea());
        loginUser.setEmail(addUser.getEmail());
        loginUser.setPhone(addUser.getPhone());
        List<Long> roles = new ArrayList<>();
        switch (loginUser.getType()) {
            case AccountType.CityManager://城市运营商才能建立酒店
                roles.clear();
                roles.add(SysRoleType.HotelManager.getIndex());
                loginUser.setRoleIdList(roles);
                loginUser.setType(AccountType.HotelManager);
                loginUser.setDeptId(AccountType.HotelManager);
                break;
            case AccountType.CityAgent://市代理才能建立城市运营商
                roles.clear();
                roles.add(SysRoleType.CityManager.getIndex());
                loginUser.setRoleIdList(roles);
                loginUser.setType(AccountType.CityManager);
                loginUser.setDeptId(AccountType.CityManager);
                loginUser.setCountryCode(addUser.getCountryCode());
                break;
            case AccountType.ProvinceManager://省代理才能建立市代理
                roles.clear();
                roles.add(SysRoleType.CityAgent.getIndex());
                loginUser.setRoleIdList(roles);
                loginUser.setType(AccountType.CityAgent);
                loginUser.setDeptId(AccountType.CityAgent);
                loginUser.setCityCode(addUser.getCityCode());
                break;
            case AccountType.Administrator://总公司才能建立省代理
                roles.clear();
                roles.add(SysRoleType.ProvinceManager.getIndex());
                loginUser.setRoleIdList(roles);
                loginUser.setType(AccountType.ProvinceManager);
                loginUser.setDeptId(AccountType.ProvinceManager);
                loginUser.setProvinceCode(addUser.getProvinceCode());
                break;
            default:
                throw new ServiceException("无操作权限");
        }
        messageService.createAccount(Long.valueOf(loginUser.getId()));
        saveUser(loginUser);
    }


    /**
     * web 添加【运营商/服务商/卡商】账户服务接口
     *
     * @param loginUser 当前操作用户
     * @param param     输入参数
     */
    @Override
    public void saveBusiness(AccountInfo loginUser, AddBusinessParam param) {
        //存入其他信息
        AccountInfo accountInfo = convertAddParam(param);
        //根据不同类型存储信息
        if (null != accountInfo) {
            List<Long> roles = Lists.newArrayList();
            if (loginUser.getType() == AccountType.Administrator) {
                //总公司都可以添加
                accountInfo = adminConvert(accountInfo, roles);
            } else if (loginUser.getType() == AccountType.OperateMerchant) {
                //只能添加服务商和卡商
                accountInfo = operateConvert(accountInfo, roles);
            } else if (loginUser.getType() == AccountType.MinOperateMerchant) {
                //小V运营商
                accountInfo = minOperateConvert(accountInfo, roles);
            }
            messageService.createAccount(Long.valueOf(loginUser.getId()));
            //添加相关比例，角色信息
            saveBusiness(loginUser, accountInfo);
        }
    }

    /**
     * 总公司添加相关服务商判断
     *
     * @param accountInfo 账户信息
     * @param roles       角色信息
     * @return
     */
    private AccountInfo adminConvert(AccountInfo accountInfo, List<Long> roles) {
        switch (accountInfo.getType()) {
            case AccountType.OperateMerchant:
                //添加运营商
                roles.clear();
                roles.add(SysRoleType.OPERATE_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.OperateMerchant);
                //查询部门Id（根据角色查询）
                SysRole sysRole = sysRoleService.getById(AccountType.OperateMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            case AccountType.VipCardMerchant:
                //添加卡商
                roles.clear();
                roles.add(SysRoleType.VIP_CARD_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.VipCardMerchant);
                sysRole = sysRoleService.getById(AccountType.VipCardMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            case AccountType.MinOperateMerchant:
                //添加“小V”运营商
                roles.clear();
                roles.add(SysRoleType.MIN_OPERATE_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.MinOperateMerchant);
                //查询部门Id（根据角色查询）
                sysRole = sysRoleService.getById(AccountType.MinOperateMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            case AccountType.MinVipCardMerchant:
                //添加“小V”卡商
                roles.clear();
                roles.add(SysRoleType.MIN_VIP_CARD_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.MinVipCardMerchant);
                sysRole = sysRoleService.getById(AccountType.MinVipCardMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            default:
                throw new ServiceException("无操作权限");
        }

        return accountInfo;
    }

    /**
     * 运营商添加相关卡商判断
     *
     * @param accountInfo
     * @param roles
     * @return
     */
    private AccountInfo operateConvert(AccountInfo accountInfo, List<Long> roles) {

        //只能添加服务商和卡商
        switch (accountInfo.getType()) {
            case AccountType.VipCardMerchant:
                //添加卡商
                roles.clear();
                roles.add(SysRoleType.VIP_CARD_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.VipCardMerchant);
                SysRole sysRole = sysRoleService.getById(AccountType.VipCardMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            default:
                throw new ServiceException("无操作权限");
        }

        return accountInfo;
    }

    /**
     * 小V运营商添加相关卡商判断
     *
     * @param accountInfo
     * @param roles
     * @return
     */
    private AccountInfo minOperateConvert(AccountInfo accountInfo, List<Long> roles) {

        //只能添加小V服务商和小V卡商
        switch (accountInfo.getType()) {
            case AccountType.MinVipCardMerchant:
                //添加卡商
                roles.clear();
                roles.add(SysRoleType.MIN_VIP_CARD_MERCHANT.getIndex());
                accountInfo.setRoleIdList(roles);
                accountInfo.setType(AccountType.MinVipCardMerchant);
                SysRole sysRole = sysRoleService.getById(AccountType.MinVipCardMerchant);
                accountInfo.setDeptId(sysRole.getDeptId().intValue());
                break;
            default:
                throw new ServiceException("无操作权限");
        }

        return accountInfo;
    }

    /**
     * 完善公共添加信息
     *
     * @param param 添加的参数
     * @return 返回结果
     */
    private AccountInfo convertAddParam(AddBusinessParam param) {
        AccountInfo accountInfo = ObjectConvertUtil.convertObject(param, AccountInfo.class);
        //存入地址信息
        JsonHotelPayAccounts extraInfo = new JsonHotelPayAccounts();
        extraInfo.setAddressDetail(param.getAddressDetail());
        assert accountInfo != null;
        accountInfo.setExtraInfo(JSON.toJSONString(extraInfo));

        return accountInfo;
    }

    @Override
    public List<AccountInfo> listBusiness(QueryBusinessParam param, AccountInfo loginUser) {
        //验证相关的参数信息
        validQueryBusinessParam(param);
        //分页查询

        List<AccountInfo> accountInfoList = Lists.newArrayList();
        if (loginUser.getType() == AccountType.Administrator) {
            PageHelper.startPage(param.getPageNum(), param.getPageSize());
            accountInfoList = accountInfoMapper.queryBusinessByPage(param.getType(),
                    param.getName(), param.getUsername(), null);
        } else {
            //得到运营商子集的accountIds
            List<Integer> accountIdList = accountVipSalerRelationService.listByChildren(loginUser);
            if (!CollectionUtils.isEmpty(accountIdList)) {
                PageHelper.startPage(param.getPageNum(), param.getPageSize());
                accountInfoList = accountInfoMapper.queryBusinessByPage(param.getType(),
                        param.getName(), param.getUsername(), accountIdList);
            }
        }
        if (!CollectionUtils.isEmpty(accountInfoList)) {
            accountInfoList.forEach(accountInfo -> {
                if (!StringUtils.isEmpty(accountInfo.getExtraInfo())) {
                    JsonHotelPayAccounts extraInfo = JSON.parseObject(accountInfo.getExtraInfo(), JsonHotelPayAccounts.class);
                    if (null != extraInfo && !StringUtils.isEmpty(extraInfo.getAddressDetail())) {
                        accountInfo.setAddressDetail(extraInfo.getAddressDetail());
                    }
                }
            });
        }
        if (param.getType() == AccountType.MinVipCardMerchant) {
            convertParentName(accountInfoList);
        }
        //组装父类名称
        return accountInfoList;
    }

    /**
     * 补充父类名称
     *
     * @param accountInfoList 账户列表
     */
    private void convertParentName(List<AccountInfo> accountInfoList) {

        if (!CollectionUtils.isEmpty(accountInfoList)) {
            accountInfoList.forEach(accountInfo -> {
                AccountVipSalerRelation accountVipSalerRelation = accountVipSalerRelationMapper.selectOne(new QueryWrapper<AccountVipSalerRelation>()
                        .eq(AccountVipSalerRelation.ACCOUNT_ID, accountInfo.getId()));
                if (null != accountVipSalerRelation && accountVipSalerRelation.getParentId() != null) {
                    AccountInfo parentAccount = baseMapper.selectOne(new QueryWrapper<AccountInfo>()
                            .eq(AccountInfo.ID, accountVipSalerRelation.getParentId()));
                    accountInfo.setParentName(parentAccount.getUsername());
                }
            });
        }
    }

    @Override
    public int countBusiness(QueryBusinessParam param, AccountInfo loginUser) {

        validQueryBusinessParam(param);
        int count = 0;
        if (loginUser.getType() == AccountType.Administrator) {
            count = accountInfoMapper.queryCountByBusiness(param.getType(),
                    param.getName(), param.getUsername(), null);
        } else {
            //得到运营商子集的accountIds
            List<Integer> accountIdList = accountVipSalerRelationService.listByChildren(loginUser);
            if (!CollectionUtils.isEmpty(accountIdList)) {
                count = accountInfoMapper.queryCountByBusiness(param.getType(),
                        param.getName(), param.getUsername(), accountIdList);
            }
        }
        return count;
    }

    private void validQueryBusinessParam(QueryBusinessParam param) {

        if (param.getType() == null) {
            throw new ServiceException("账户类型不能为空");
        }
        if (!Lists.newArrayList(AccountType.OperateMerchant,
                AccountType.VipCardMerchant,
                AccountType.MinOperateMerchant,
                AccountType.MinVipCardMerchant).contains(param.getType())) {
            throw new ServiceException("账户类型为" + param.getType() + "不存在");
        }
    }


    @Override
    public void saveUserHotel(AccountInfo loginUser) {
        messageService.createAccount(null == loginUser.getId() ? null : Long.valueOf(loginUser.getId()));
        saveUser(loginUser);
    }

    @Override
    public AccountInfo findByPrimaryKey(Integer id) {
        return accountInfoMapper.selectByPrimaryKey(id);
    }


    @Override
    public List<Long> queryAllMenuId(Integer userId) {
        return baseMapper.queryAllMenuId(userId);
    }

    @Override
    public List<AccountInfo> queryNoRoleUser(Integer type) {
        return baseMapper.queryNoRoleUser(type);
    }

    @Override
    public List<AccountInfo> queryDeveloper(String name, Integer accountType) {
        return baseMapper.queryDeveloper(name, accountType);
    }

    @Override
    public List<AccountInfo> queryAgent(String area, Integer accountType) {
        QueryWrapper<AccountInfo> queryWrapper = new QueryWrapper<AccountInfo>().eq(AccountInfo.TYPE, accountType).like(AccountInfo.AREA, area);

        List<AccountInfo> accountInfos = list(queryWrapper);

        return accountInfos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(AccountInfo user) {
        if (AccountType.ProvinceManager == user.getType()) {
            user.setC2bRate(AccountInfoRateEnum.MattressRate.ProvinceManager.value());
        } else if (AccountType.CityAgent == user.getType()) {
            user.setC2bRate(AccountInfoRateEnum.MattressRate.CityAgent.value());
        } else if (AccountType.CityManager == user.getType()) {
            user.setC2bRate(AccountInfoRateEnum.MattressRate.CityManager.value());
        }
        user.setGmtCreate(new Date());
        user.setGmtModified(new Date());
        this.save(user);

        //保存用户与角色关系
        sysUserRoleService.saveOrUpdate(Long.valueOf(user.getId()), user.getRoleIdList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveBusiness(AccountInfo loginUser, AccountInfo accountInfo) {
        accountInfo.setGmtCreate(new Date());
        accountInfo.setGmtModified(new Date());
        this.save(accountInfo);

        //保存用户与角色关系
        sysUserRoleService.saveOrUpdate(Long.valueOf(accountInfo.getId()), accountInfo.getRoleIdList());
        //添加相关的比例信息(需要创建相关对象信息)
        vipCommissionRateConfigService.addVipCommissionRateConfig(accountInfo.getId(), 2);
        //添加服务商卡商的所属关系，如果是总公司,不进行添加
        AccountVipSalerRelation vipSalerRelation = null;
        if (loginUser.getType() == AccountType.OperateMerchant) {
            vipSalerRelation = new AccountVipSalerRelation();
            vipSalerRelation.setVipType(1);
            vipSalerRelation.setCreateTime(new Date());
            vipSalerRelation.setAccountId(accountInfo.getId());
            vipSalerRelation.setParentId(loginUser.getId());
            accountVipSalerRelationMapper.insert(vipSalerRelation);
        } else if (loginUser.getType() == AccountType.MinOperateMerchant) {
            //添加小V之间的关系信息
            vipSalerRelation = new AccountVipSalerRelation();
            vipSalerRelation.setVipType(2);
            vipSalerRelation.setCreateTime(new Date());
            vipSalerRelation.setAccountId(accountInfo.getId());
            vipSalerRelation.setParentId(loginUser.getId());
            accountVipSalerRelationMapper.insert(vipSalerRelation);
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(AccountInfo user) {
//		if(StringUtils.isBlank(user.getPassword())){
//			user.setPassword(null);
//		}else{
//			AccountInfo userEntity = this.getById(user.getId());
//		//	user.setPassword(ShiroUtils.sha256(user.getPassword(), userEntity.getSalt()));
//		}
        this.updateById(user);

        //保存用户与角色关系
        sysUserRoleService.saveOrUpdate(Long.valueOf(user.getId()), user.getRoleIdList());
    }

    @Override
    public int updateNotNullField(AccountInfo user) {
        return baseMapper.updateById(user);
    }


    @Override
    public boolean updatePassword(Long userId, String password, String newPassword) {
        AccountInfo userEntity = new AccountInfo();
        userEntity.setPassword(newPassword);
        return this.update(userEntity,
                new QueryWrapper<AccountInfo>().eq("id", userId));
    }

    @Override
    public boolean updateValid(Long userId, boolean valid) {
        AccountInfo userEntity = new AccountInfo();
        userEntity.setValid(valid);
        return this.update(userEntity,
                new QueryWrapper<AccountInfo>().eq("id", userId));
    }

    /**
     * token秘钥
     */
    public static final String SECRET = "269e2643-b259-419c-bc4d-23b34d09f9f4";

    /**
     * 解密Token，获得内容
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Map<String, Claim> getClaims(String token) {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT jwt = verifier.verify(token);
        return (jwt == null || jwt.getClaims() == null) ? null : jwt.getClaims();
    }

    /**
     * 根据Token获取user_id
     *
     * @param token
     * @return user_id
     */
    @Override
    public String getUserId(String token) throws TokenInvalidException {

        String user_id = null;
        try {
            Map<String, Claim> claims = getClaims(token);
            Claim user_id_claim = claims.get("user_id");
            user_id = user_id_claim == null ? null : user_id_claim.asString();
        } catch (Throwable e) {
            e.printStackTrace();
        }

        if (user_id == null) {
            throw new TokenInvalidException();
        }
        return user_id;
    }


    /**
     * 查询父id
     *
     * @param id
     * @return
     */
    @Override
    public List<Integer> getParentId(Integer id) {
        return baseMapper.selectAllParentId(id);
    }

    /**
     * 通过账户id获取账户信息
     *
     * @param userId
     * @return
     */
    @Override
    public AccountInfo selectByPrimaryKey(Integer userId) {
        return baseMapper.selectById(userId);
    }

    /**
     * 通过账户id获取账户信息
     *
     * @param ids
     * @return
     */
    @Override
    public List<AccountInfo> selectByIds(List<Integer> ids) {
        return baseMapper.selectByIds(ids);
    }

    @Override
    public List<Long> selectRoleIdList(Integer userId) {

        return accountInfoMapper.selectRoleIdList(userId);
    }


    @Override
    public UserInfo tokenUserInfo(String token) {
        UserInfo userInfo = null;
        try {
            Integer userId = token2UserId(token);
            userInfo = userInfoMapper.selectById(userId);
        } catch (Exception e) {
            log.info("通过用户token获取用户失败，token=" + token + "，错误信息：" + e.getMessage());
        }
        if (userInfo == null) {
            log.info("token过期，请重新登陆，token={}", token);
            throw new ServiceException(ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode(), "用户信息失效，请重新登陆");
        }
        return userInfo;
    }

    @Override
    public CommonResult updateAccountCode(Integer status) {

        List<AccountInfo> accountInfoList;
        //查询出没有省市区县的code的数据
        if (status == 1) {
            accountInfoList = accountInfoMapper.selectList(new QueryWrapper<AccountInfo>()
                    .isNull(AccountInfo.PROVINCE_CODE).or().isNull(AccountInfo.CITY_CODE).or().isNull(AccountInfo.COUNTRY_CODE));
        } else {
            accountInfoList = accountInfoMapper.selectList(null);
        }
        int count = 0;
        if (!CollectionUtils.isEmpty(accountInfoList)) {
            //数据拼装完善地址的code
            accountInfoList.forEach(accountInfo -> {
                if (accountInfo.getArea() != null && !"".equals(accountInfo.getArea())) {
                    //循环更新数据信息, 得到code值
                    AppAddressCode appAddressCode = addressDivisionService.getEntityCode(accountInfo.getArea(), null);
                    if (null != appAddressCode) {
                        //省
                        accountInfo.setProvinceCode(appAddressCode.getProvinceCode());
                        //市
                        if (!StringUtils.isEmpty(appAddressCode.getCityCode())) {
                            accountInfo.setCityCode(appAddressCode.getCityCode());
                            //区/县
                            if (!StringUtils.isEmpty(appAddressCode.getCountyCode())) {
                                accountInfo.setCountryCode(appAddressCode.getCountyCode());
                            }
                        }
                    }
                }
            });
            count = accountInfoMapper.updateAccountCodeBatch(accountInfoList);
        }
        if (count > 0) {
            return CommonResult.success(null, "批量更新地址成功");
        }
        return CommonResult.failed("批量更新Code失败");
    }

    @Override
    public CommonResult updatePwd(UpdatePwdParam updatePwdParam, AccountInfo accountInfo) {

        //密码参数验证
        CommonResult pwdParamResult = this.validUpdateParam(updatePwdParam, accountInfo);
        if (pwdParamResult.getCode() != CommonResult.SUCCESS) {
            return pwdParamResult;
        }

        //修改数据库密码
        int count = accountInfoMapper.update(new AccountInfo().setPassword(updatePwdParam.getConfirmPwd()),
                new UpdateWrapper<AccountInfo>().eq(AccountInfo.ID, accountInfo.getId()));
        if (count > 0) {
            //清除token
            redisService.remove(BuilderKey.build(ACCOUNT_TOKEN, accountInfo.getId()));
            return CommonResult.success(null, "修改密码成功");
        }

        return CommonResult.failed("修改密码失败");
    }

    @Override
    public CommonResult<CommonPage<AppAccountDTO>> queryList(QueryAccountParam param, AccountInfo accountInfo) {

        return CommonResult.success(convertCommonPage(param, accountInfo));
    }

    /**
     * 分页查询运营商和卡商列表信息
     *
     * @param param     查询条件
     * @param loginUser 操作人
     * @return
     */
    @Override
    public CommonResult<CommonPage<AppAccountDTO>> queryPageAppBusiness(AppQueryBusinessParam param, AccountInfo loginUser) {

        if (loginUser.getType() != AccountType.Administrator) {
            throw new OftenFiledException("暂无权限操作！");
        }
        QueryAccountParam convert = MyBeanUtils.convert(param, QueryAccountParam.class);
        convert.setKeyword(param.getKeywords());
        CommonPage<AppAccountDTO> appAccountDTOCommonPage =
                this.convertCommonPage(convert, loginUser);
        //查询运营商的售卡数量
        if (!CollectionUtils.isEmpty(appAccountDTOCommonPage.getList())) {
            appAccountDTOCommonPage.getList().forEach(appAccountDTO -> {
                if (appAccountDTO.getType() == AccountType.MinOperateMerchant ||
                        appAccountDTO.getType() == AccountType.MinVipCardMerchant) {
                    appAccountDTO.setSaleCardCount(getSaleCardCountBySalerId(appAccountDTO.getId()));
                }
            });
        }
        return CommonResult.success(appAccountDTOCommonPage);
    }

    /**
     * 卡运营商列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<MemberCardOperatorListResult> selectOperatorList(MemberCardOperatorListParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        QueryWrapper<AccountInfo> wrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(param.getUsername())) {
            wrapper.like(AccountInfo.USERNAME, param.getUsername());
        }
        wrapper.eq(AccountInfo.VALID, 1).in(AccountInfo.TYPE, AccountType.MinOperateMerchant, AccountType.MinVipCardMerchant).orderByDesc(AccountInfo.GMT_CREATE);
        List<AccountInfo> accountInfos = baseMapper.selectList(wrapper);
        PageInfo<AccountInfo> pageInfo = PageInfo.of(accountInfos);
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), pageInfo.isHasNextPage(), pageInfo.getNextPage(), ObjectConvertUtil.convertList(accountInfos, MemberCardOperatorListResult.class));
    }

    /**
     * 查询该运营商售出的卡片数量
     *
     * @param accountId 运营商ID
     * @return 返回结果
     */
    private int getSaleCardCountBySalerId(Integer accountId) {

        int count = memberCardService.count(new QueryWrapper<MemberCard>()
                .eq(MemberCard.SALER_ID, accountId).eq(MemberCard.ENABLE, 1));
        if (count > 0) {
            return count;
        }
        return 0;
    }

    /**
     * 分页具体实现
     *
     * @return
     */
    private CommonPage<AppAccountDTO> convertCommonPage(QueryAccountParam param, AccountInfo accountInfo) {
        CommonPage<AppAccountDTO> appAccountDTOCommonPage = new CommonPage<AppAccountDTO>();
        String areaType = null;
        if (!StringUtils.isEmpty(param.getDivCode())) {
            areaType = getAreaType(param.getDivCode());
        }

        //组装查询参数
        Map<String, Object> queryMap = convertQueryMap(param, accountInfo);
        queryMap.put("areaType", areaType);
        List<AccountInfo> accountInfoList = Lists.newArrayList();
        if (param.getType() == AccountType.MinOperateMerchant || param.getType() == AccountType.MinVipCardMerchant) {
            PageHelper.startPage(param.getPageNum(), param.getPageSize());
            //分页参数设置
            accountInfoList = accountInfoMapper.selectBusinessPageByMap(queryMap);
        } else {
            PageHelper.startPage(param.getPageNum(), param.getPageSize());
            //分页参数设置
            accountInfoList = accountInfoMapper.selectPageByMap(queryMap);
        }
        if (!CollectionUtils.isEmpty(accountInfoList)) {
            CommonPage<AccountInfo> accountInfoCommonPage = CommonPage.restPage(param.getPageNum(),
                    param.getLastId(), accountInfoList);
            appAccountDTOCommonPage = MyBeanUtils.convertCommonPageList(accountInfoCommonPage, AppAccountDTO.class);

            //得到子类的个数（如果是运营商，个数发生变化）
            if (param.getType() == AccountType.MinOperateMerchant) {
                appAccountDTOCommonPage.getList().forEach(appAccountDTO -> {
                    appAccountDTO.setGrandchildrenCount(this.getDeveloperCount(appAccountDTO));
                });
            } else {
                appAccountDTOCommonPage.getList().forEach(appAccountDTO -> {
                    appAccountDTO.setGrandchildrenCount(this.getChildrenCount(appAccountDTO));
                });
            }
        }
        return appAccountDTOCommonPage;
    }

    @Override
    public CommonResult<CommonPage<AppAccountDTO>> queryChildList(QueryChildAccountParam queryChildAccountParam, AccountInfo accountInfo) {

        CommonPage<AppAccountDTO> appAccountDTOCommonPage = new CommonPage<AppAccountDTO>();
        PageHelper.startPage(queryChildAccountParam.getPageNum(), queryChildAccountParam.getPageSize());
        List<AccountInfo> accountInfoList = accountInfoMapper.selectChildAccountPageByAccountId(accountInfo.getId());
        if (!CollectionUtils.isEmpty(accountInfoList)) {
            CommonPage<AccountInfo> couponInfoCommonPage = CommonPage.restPage(queryChildAccountParam.getPageNum(),
                    queryChildAccountParam.getLastId(), accountInfoList);
            appAccountDTOCommonPage = MyBeanUtils.convertCommonPageList(couponInfoCommonPage, AppAccountDTO.class);
        }
        return CommonResult.success(appAccountDTOCommonPage);
    }

    @Override
    public CommonResult setValid(SetAccountValidParam setAccountValidParam, AccountInfo convert, Boolean valid) {

        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(setAccountValidParam.getAccountId());
        if (null != accountInfo) {
            if (accountInfo.getType() == AccountType.Administrator) {
                return CommonResult.failed("总公司不可禁用！");
            }
            //判断是否启用 是否有值
            if (null == valid) {
                accountInfo.setValid(setAccountValidParam.getValid());
            } else {
                accountInfo.setValid(valid);
            }
            int count = accountInfoMapper.updateById(accountInfo);
            if (count > 0) {
                //清空该账户的token, 并且不能登录
                String key = BuilderKey.build(ACCOUNT_TOKEN, accountInfo.getId());
                redisService.remove(key);
                return CommonResult.success("操作账号状态成功");
            }
        }
        return CommonResult.failed("设置账号状态失败！");

    }

    @Override
    public CommonResult<AppAccountDTO> getAccount(GetAccountParam getAccountParam, AccountInfo convert) {

        AppAccountDTO accountDTO = new AppAccountDTO();

        if (null != convert) {
            accountDTO = MyBeanUtils.convert(convert, AppAccountDTO.class);

            CommonResult<String> addressCommonResult = addressDivisionService.getAddressCodeByDetailAddress(convert.getArea());
            String divCode = null;
            if (addressCommonResult.getData() != null && !"".equals(addressCommonResult.getData())) {
                divCode = addressCommonResult.getData();
            }
            accountDTO.setDivCode(divCode);
            List<AppRouteDTO> appRouteDTOList = sysAppMenuService.selectByAccountId(Long.valueOf(accountDTO.getId()));
            accountDTO.setRouteList(appRouteDTOList);
        }
        return CommonResult.success(accountDTO);
    }

    @Override
    public CommonResult<JsonBankInfo> getBankInfoByToken(GetPayAccountsParam getPayAccountsParam, AccountInfo accountInfo) {

        JsonBankInfo jsonBankInfo = new JsonBankInfo();
        if (null != accountInfo && !StringUtils.isEmpty(accountInfo.getExtraInfo())) {
            JSONObject jsonObject = JSONObject.parseObject(accountInfo.getExtraInfo());
            log.info("数据信息" + jsonObject.get("pay_accounts").toString());
            jsonBankInfo = JSONObject.parseObject(String.valueOf(jsonObject.get("pay_accounts")), JsonBankInfo.class);
        }
        return CommonResult.success(jsonBankInfo);
    }


    @Override
    public AccountInfo loginAccount(String username, String password) {

        return accountInfoMapper.loginAccount(username, password);
    }

    @Override
    public CommonResult forgetPwd(ForgetPwdParam forgetPwdParam, AccountInfo accountInfo) {

        int update = accountInfoMapper.update(new AccountInfo().setPassword(forgetPwdParam.getConfirmPwd()),
                new QueryWrapper<AccountInfo>().eq(AccountInfo.ID, accountInfo.getId()));
        if (update > 0) {
            //清除token
            redisService.remove(BuilderKey.build(ACCOUNT_TOKEN, accountInfo.getId()));
            return CommonResult.success(null, "修改密码成功");
        }
        return CommonResult.failed("更新密码失败");
    }

    /**
     * 通过酒店id查询该酒店账户对应的上级用户id
     *
     * @param hotelId
     * @return
     */
    @Override
    public List<Integer> selectParentIdByHotelId(Integer hotelId) {
        HotelInfo hotelInfo = hotelInfoService.getById(hotelId);
        if (null == hotelInfo) {
            return Lists.newArrayList();
        }
        return getParentId(hotelInfo.getOperatorId());
    }

    /**
     * 通过酒店id查询该酒店账户对应的上级用户id(不包括酒店账户id)
     *
     * @param hotelId
     * @return
     */
    @Override
    public List<Integer> selectExcludeParentIdByHotelId(Integer hotelId) {
        HotelInfo hotelInfo = hotelInfoService.getById(hotelId);
        if (null == hotelInfo) {
            return Lists.newArrayList();
        }
        List<Integer> accountIds = getParentId(hotelInfo.getOperatorId());
        accountIds.remove(hotelInfo.getOperatorId());
        return accountIds;
    }

    /**
     * 通过酒店id查询该酒店账户对应的所有上级(不包括酒店账户id)
     *
     * @param hotelId
     * @return （key账户id， value为账户类型）
     */
    @Override
    public Map<Integer, Integer> selectExcludeParentIdAndTypeByHotelId(Integer hotelId) {
        List<Integer> accountIds = selectExcludeParentIdByHotelId(hotelId);
        if (null == accountIds) {
            return Maps.newHashMap();
        }
        return getIdAndType(accountIds);
    }

    /**
     * 通过账户id查询该账户对应的所有上级(不包括当前账户)
     *
     * @param accountId
     * @return （key账户id， value为账户类型）
     */
    @Override
    public Map<Integer, Integer> selectExcludeParentIdAndTypeById(Integer accountId) {
        List<Integer> accountIds = getParentId(accountId);
        accountIds.remove(accountId);
        return getIdAndType(accountIds);
    }

    /**
     * 根据accountIds获取map(key账户id， value为账户类型)
     *
     * @param accountIds
     * @return
     */
    @Override
    public Map<Integer, Integer> getIdAndType(List<Integer> accountIds) {
        List<AccountInfo> accountInfos = baseMapper.selectByIds(accountIds);
        if (null == accountInfos) {
            return Maps.newHashMap();
        }
        Map<Integer, Integer> map = Maps.newHashMap();
        for (AccountInfo accountInfo : accountInfos) {
            map.put(accountInfo.getId(), accountInfo.getType());
        }
        return map;
    }


    /**
     * 通过部门老大id查询所有子账户id
     *
     * @param manageId 父账户id
     * @return
     */
    @Override
    public List<Integer> selectChildByManageId(Integer manageId) {
        if (null == manageId) {
            return Lists.newArrayList();
        }
        List<AccountInfo> accountInfos = baseMapper.selectList(new QueryWrapper<AccountInfo>()
                .eq(AccountInfo.MANAGER_ID, manageId)
                .eq(AccountInfo.VALID, 1));
        if (null == accountInfos || accountInfos.size() == 0) {
            return Lists.newArrayList();
        }
        return Lists.transform(accountInfos, AccountInfo::getId);
    }

    @Override
    public List<AccountInfo> getSalerList(String name, Integer hotelId, Integer vipType) {


        HotelInfo hotelInfo = hotelInfoService.getOne(new QueryWrapper<HotelInfo>().eq(HotelInfo.ID, hotelId));
        if (null == hotelInfo) {
            throw new ServiceException("酒店Id无效");
        }

        List<Integer> accountIds = Lists.newArrayList();
        if (hotelInfo.getDeveloperId() != null) {
            //根据开发商的Id查询下面的服务商，卡商，包含自己
            List<AccountVipSalerRelation> vipSalerRelationList = accountVipSalerRelationMapper.selectList(new QueryWrapper<AccountVipSalerRelation>()
                    .eq(AccountVipSalerRelation.PARENT_ID, hotelInfo.getDeveloperId()));
            if (!CollectionUtils.isEmpty(vipSalerRelationList)) {
                accountIds = vipSalerRelationList.stream().map(AccountVipSalerRelation::getAccountId).collect(Collectors.toList());
            }
            accountIds.add(hotelInfo.getDeveloperId());
        }

        QueryWrapper<AccountInfo> qw = new QueryWrapper<AccountInfo>();
        if (vipType == 1) {
            qw.in(AccountInfo.TYPE, Lists.newArrayList(AccountType.OperateMerchant, AccountType.VipCardMerchant));
        } else if (vipType == 2) {
            qw.in(AccountInfo.TYPE, Lists.newArrayList(AccountType.MinOperateMerchant, AccountType.MinVipCardMerchant));
        }
        qw.eq(AccountInfo.VALID, 1);
        if (!StringUtils.isEmpty(name)) {
            qw.like(AccountInfo.USERNAME, name);
        }
        if (!CollectionUtils.isEmpty(accountIds)) {
            qw.in(AccountInfo.ID, accountIds);
        }

        return accountInfoMapper.selectList(qw);
    }

    /**
     * 通过账户id和账户类型查询账户信息
     *
     * @param accountId
     * @param accountType
     * @return
     */
    @Override
    public AccountInfo selectByIdAndType(Integer accountId, Integer accountType) {
        return baseMapper.selectOne(new QueryWrapper<AccountInfo>().eq(AccountInfo.ID, accountId).eq(AccountInfo.TYPE, accountType).last("limit 1"));
    }

    /**
     * 通过账户id和账户类型查询佣金比例
     *
     * @param accountId   账户id
     * @param accountType 账户类型
     * @param type        1c2b, 2mattress
     * @param totalAmount 金额
     * @return
     */
    @Override
    public Integer selectByIdAndType(Integer accountId, Integer accountType, Integer type, Integer totalAmount) {
        totalAmount = totalAmount == null ? 0 : totalAmount;
        if (totalAmount <= 0) {
            return 0;
        }
        AccountInfo accountInfo = selectByIdAndType(accountId, accountType);
        if (null == accountInfo) {
            return 0;
        }
        Integer rate = null;
        if (1 == type) {
            rate = accountInfo.getC2bRate();
        } else {
            rate = accountInfo.getMattressRate();
        }
        if (null == rate) {
            if (AccountInfoTypeEnum.ProvinceManager.value().equals(accountType)) {
                //c2b
                if (1 == type) {
                    rate = AccountInfoRateEnum.C2bRate.ProvinceManager.value();
                } else {//mattress
                    rate = AccountInfoRateEnum.MattressRate.ProvinceManager.value();
                }
            }
            if (AccountInfoTypeEnum.CityAgent.value().equals(accountType)) {
                //c2b
                if (1 == type) {
                    rate = AccountInfoRateEnum.C2bRate.CityAgent.value();
                } else {//mattress
                    rate = AccountInfoRateEnum.MattressRate.CityAgent.value();
                }
            }
            if (AccountInfoTypeEnum.CityManager.value().equals(accountType)) {
                //c2b
                if (1 == type) {
                    rate = AccountInfoRateEnum.C2bRate.CityManager.value();
                } else {//mattress
                    rate = AccountInfoRateEnum.MattressRate.CityManager.value();
                }
            }
        }
        Integer amount = FormatUtils.amountToRateV2(totalAmount, rate);
        return amount == null ? 0 : amount;
    }

    /**
     * 查询优享VIP 【开发商】
     *
     * @param name        名称 [名称精确查询]
     * @param developType 1, 臻享开发商， 2，优享开发商
     * @return
     */
    @Override
    public List<AccountInfo> findDeveloper(String name, Integer developType) {

        return baseMapper.findDeveloper(name, developType);
    }


    /**
     * 查询条件的拼装
     *
     * @param param       查询参数
     * @param accountInfo 账户信息
     * @return 返回结果
     */
    private Map<String, Object> convertQueryMap(QueryAccountParam param, AccountInfo accountInfo) {

        Map<String, Object> queryMap = Maps.newHashMap();
        if (null != param) {
            queryMap = ObjectConvertUtil.objectToMap(param);
        }
        assert queryMap != null;
        queryMap.put("id", accountInfo.getId());
        queryMap.put("operatorType", accountInfo.getType());

        return queryMap;
    }

    /**
     * 得到子类的个数
     * 1.这个查询有点臃肿，效率也不是很高，后期需要更新
     */
    private int getChildrenCount(AppAccountDTO info) {
        int childrenCount = 0;
        if (null != info) {
            switch (info.getType()) {
                //省代
                case 2:
                    //查询签约酒店
                    childrenCount = accountInfoMapper.countOfGrandchildchildren(info.getId(), null, null);
                    break;
                //市代
                case 3:
                    childrenCount = accountInfoMapper.countOfGrandchildren(info.getId(), null, null);
                    break;
                //区县
                case 4:
                    childrenCount = accountInfoMapper.countOfChildren(info.getId(), null, null);
                    break;
                default:
                    break;
            }
        }
        return childrenCount;
    }

    /**
     * 计算运营商关联酒店数据量
     *
     * @param info
     * @return
     */
    private int getDeveloperCount(AppAccountDTO info) {

        int count = hotelInfoService.count(new QueryWrapper<HotelInfo>().eq(HotelInfo.DEVELOPER_ID, info.getId()));
        if (count > 0) {
            return count;
        }
        return 0;
    }

    /**
     * 根据code判断这个Code属于 省 、 市 、 区县
     *
     * @param divCode
     * @return 1 省 2 市 3 区/县
     */
    private String getAreaType(String divCode) {

        CommonResult<AppAddressDTO> addressDTOCommonResult = addressDivisionService.getAddressByDivId(divCode);
        if (null != addressDTOCommonResult.getData()) {
            return addressDTOCommonResult.getData().getDivLevel();
        }
        return null;
    }


    /**
     * 验证修改密码参数
     *
     * @param updatePwdParam 密码参数
     * @return 返回信息
     */
    private CommonResult validUpdateParam(UpdatePwdParam updatePwdParam, AccountInfo accountInfo) {

        if (!updatePwdParam.getOldPwd().equals(accountInfo.getPassword())) {
            return CommonResult.failed("旧密码不正确");
        }

        if (updatePwdParam.getOldPwd().equals(updatePwdParam.getNewPwd())) {
            return CommonResult.failed("新密码不能和旧密码一致");
        }

        if (!updatePwdParam.getNewPwd().equals(updatePwdParam.getConfirmPwd())) {
            return CommonResult.failed("两次密码不一致");
        }

        return CommonResult.success(null, "参数验证通过");
    }


}
